View Javadoc

1   package nl.toolforge.karma.console;
2   
3   import nl.toolforge.karma.core.ErrorCode;
4   import nl.toolforge.karma.core.boot.LocationStore;
5   import nl.toolforge.karma.core.boot.ManifestStore;
6   import nl.toolforge.karma.core.boot.Store;
7   import nl.toolforge.karma.core.boot.WorkingContext;
8   import nl.toolforge.karma.core.boot.WorkingContextConfiguration;
9   import nl.toolforge.karma.core.boot.WorkingContextException;
10  import nl.toolforge.karma.core.location.PasswordScrambler;
11  import nl.toolforge.karma.core.vc.AuthenticationException;
12  import nl.toolforge.karma.core.vc.Authenticator;
13  import nl.toolforge.karma.core.vc.AuthenticatorKey;
14  import nl.toolforge.karma.core.vc.Authenticators;
15  import nl.toolforge.karma.core.vc.VersionControlSystem;
16  import nl.toolforge.karma.core.vc.cvsimpl.CVSRepository;
17  import org.apache.commons.logging.Log;
18  import org.apache.commons.logging.LogFactory;
19  
20  import java.io.BufferedReader;
21  import java.io.File;
22  import java.io.IOException;
23  import java.io.InputStreamReader;
24  
25  /***
26   * Configures a <code>WorkingContext</code> and writes the configuration to <code>working-context.xml</code>. Required
27   * input will be asked through <code>System.in</code>.
28   *
29   * @author D.A. Smedes
30   * @version $Id: Configurator.java,v 1.6 2004/11/03 20:54:14 asmedes Exp $
31   */
32  final class Configurator {
33  
34    private Log logger = LogFactory.getLog(Configurator.class);
35  
36    private BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
37  
38    private WorkingContext context = null;
39    private WorkingContextConfiguration config = null;
40  
41    /***
42     * Constructs a <code>Configurator</code> for <code>workingContext</code>.
43     *
44     * @param config The <code>WorkingContextConfiguration</code> to configure.
45     */
46    public Configurator(WorkingContext context, WorkingContextConfiguration config) {
47  
48      this.config = config;
49      this.context = context;
50    }
51  
52    /***
53     * Configures. When this method is finished, it returns silently. If something major has happened,
54     * <code>System.exit(1)</code> will have been called.
55     */
56    public void checkConfiguration() {
57  
58      ManifestStore manifestStore = new ManifestStore(context);
59      LocationStore locationStore = new LocationStore(context);
60  
61      boolean mChecked = false;
62  
63      try {
64        checkMandatoryProperties();
65  
66        // We need some of these properties later on already.
67        //
68        context.configure(config);
69  
70        mChecked = checkManifestStoreConfiguration(manifestStore);
71  
72      } catch (IOException e) {
73        logger.error(e);
74        writeln("[ configurator ] ** Error configurating working context : " + e.getMessage());
75        System.exit(1);
76      }
77  
78      if (mChecked) {
79  
80        config.setProperty(WorkingContext.MANIFEST_STORE_MODULE, manifestStore.getModuleName());
81        config.setManifestStore(manifestStore);
82        try {
83  
84          boolean lChecked = checkLocationStoreConfiguration(locationStore);
85  
86          if (lChecked) {
87  
88            config.setProperty(WorkingContext.LOCATION_STORE_MODULE, locationStore.getModuleName());
89            config.setLocationStore(locationStore);
90  
91          } else {
92            logger.error("Could not configure location store.");
93            writeln("[ configurator ] ** Failed to configure the working context properly. Contact your administrator");
94            System.exit(1);
95          }
96        } catch (IOException e) {
97          logger.error(e);
98          writeln("[ configurator ] ** Error configurating working context : " + e.getMessage());
99          System.exit(1);
100       }
101     } else {
102       logger.error("Could not configure manifest store.");
103       writeln("[ configurator ] ** Failed to configure the working context properly. Contact your administrator");
104       System.exit(1);
105     }
106 
107     try {
108 
109       config.store();
110 
111     } catch (WorkingContextException e) {
112       logger.error("[ configurator ] ** Failed to write configuration to `working-context.xml`.");
113       System.exit(1);
114     }
115 
116   }
117 
118   private void checkMandatoryProperties() throws IOException {
119 
120     final String DEFAULT_PROJECT_BASE_DIR =
121         System.getProperty("user.home") + File.separator + "karma" + File.separator + context.getName();
122 
123     boolean ok = false;
124 
125     writeln("");
126 
127     while (!ok) {
128 
129       String newValue = null;
130 
131       String projectBaseDir = config.getProperty(WorkingContext.PROJECT_BASE_DIRECTORY_PROPERTY);
132 
133       // Does project.basedir exists as a property ?
134       //
135       if (projectBaseDir != null) {
136 
137         if (new File(projectBaseDir).canWrite()) {
138           ok = true;
139           break;
140         } else {
141           write("[ configurator ] ** Error, '" + projectBaseDir + "' is write protected.");
142         }
143       }
144 
145       projectBaseDir = (projectBaseDir == null ? DEFAULT_PROJECT_BASE_DIR : projectBaseDir);
146 
147       write("[ configurator ] What is your project base directory (" + projectBaseDir + ") : ");
148       newValue = reader.readLine().trim();
149       if (!"".equals(newValue)) {
150         projectBaseDir = newValue;
151       }
152       config.setProperty(WorkingContext.PROJECT_BASE_DIRECTORY_PROPERTY, projectBaseDir);
153 
154       ok = true;
155     }
156   }
157 
158   /***
159    * Checks the ManifestStore configuration until it is correct.
160    *
161    * @throws IOException
162    */
163   private boolean checkManifestStoreConfiguration(ManifestStore mStore) throws IOException {
164 
165     ErrorCode error = mStore.checkConfiguration();;
166 
167     int retries = 0; // Breaks the loop after three entry runs.
168     boolean quit = false;
169 
170     while (error != null && !quit) {
171 
172       if (error != null) {
173         retries++;
174         if (retries == 2) {
175           quit = true; // Set the hook to quit
176         }
177       }
178 
179       CVSRepository cvs = null;
180 
181       try {
182         cvs = (CVSRepository) mStore.getLocation();
183         if (cvs == null) {
184           cvs = new CVSRepository("manifest-store");
185         }
186       } catch (ClassCastException c) {
187         write("[ configurator ] ** Sorry, only CVS is supported in this release.");
188         cvs = new CVSRepository("manifest-store");
189       }
190 
191       cvs.setWorkingContext(context); // todo hmmm
192 
193       writeln("[ configurator ] Please configure the manifest-store !");
194 
195       configureStore(cvs, mStore);
196 
197       // Next check.
198       //
199       error = mStore.checkConfiguration();
200 
201       if (error == null) {
202         break;
203       } else {
204         writeln("[ configurator ] ** Error in manifest store configuration : " + error.getErrorMessage());
205       }
206     }
207 
208     // Its wrong when there is still an error.
209     //
210     return (error == null);
211   }
212 
213 
214   private boolean checkLocationStoreConfiguration(LocationStore lStore) throws IOException {
215 
216     ErrorCode error = lStore.checkConfiguration();
217 
218     int retries = 0; // Breaks the loop after three entry runs.
219     boolean quit = false;
220 
221     while (error != null && !quit) {
222 
223       if (error != null) {
224         retries++;
225         if (retries == 2) {
226           quit = true; // Set the hook to quit
227         }
228       }
229 
230       CVSRepository cvs = null;
231 
232       try {
233         cvs = (CVSRepository) lStore.getLocation();
234         if (cvs == null) {
235           cvs = new CVSRepository("location-store");
236         }
237       } catch (ClassCastException c) {
238         write("[ configurator ] ** Sorry, only CVS is supported in this release.");
239         cvs = new CVSRepository("location-store");
240       }
241 
242       cvs.setWorkingContext(context); // todo hmmm
243 
244       writeln("[ configurator ] Please configure the location-store !");
245 
246       configureStore(cvs, lStore);
247 
248       // Next check.
249       //
250       error = lStore.checkConfiguration();
251 
252       if (error == null) {
253         break;
254       } else {
255         writeln("[ configurator ] ** Error in location store configuration : " + error.getErrorMessage());
256       }
257     }
258 
259     // Its wrong when there is still an error.
260     //
261     return (error == null);
262   }
263 
264   private Store configureStore(CVSRepository cvs, Store store) throws IOException {
265 
266     // For Karma R1.0, we know its a CVS repo.
267     //
268     String newValue = "";
269 
270     // protocol
271     //
272     String protocol = cvs.getProtocol();
273     protocol = (protocol == null ? "pserver" : protocol);
274 
275     while (!newValue.matches("pserver|local")) {
276       write("[ configurator ] What is your server protocol ? [ local | pserver ] (" + protocol + ") : ");
277       newValue = reader.readLine().trim();
278       newValue = ("".equals(newValue) ? protocol : newValue);
279     }
280     protocol = newValue;
281     cvs.setProtocol(protocol);
282 
283     if (protocol.equals(CVSRepository.PSERVER)) {
284 
285       // Host
286       //
287       String hostName = cvs.getHost();
288       hostName = (hostName == null ? "127.0.0.1" : hostName);
289 
290       write("[ configurator ] What is your server's hostname or ip-adres ? (" + hostName + ") : ");
291       newValue = reader.readLine().trim();
292       if (!"".equals(newValue)) {
293         hostName = newValue;
294       }
295       cvs.setHost(hostName);
296 
297       // Port
298       //
299       String port = (cvs.getPort() == -1 ? "2401" : "" + cvs.getPort());
300 
301       write("[ configurator ] What is your server port ? (" + port + ") : ");
302       newValue = reader.readLine().trim();
303       if (!"".equals(newValue)) {
304         port = newValue;
305       }
306       cvs.setPort(("".equals(port) ? "2401" : port));
307     }
308 
309     // Repository
310     //
311     String repository = cvs.getRepository();
312     repository = (repository == null ? "/home/cvs" : repository);
313 
314     write("[ configurator ] What is your server repository ? (" + repository + ") : ");
315     newValue = reader.readLine().trim();
316     if (!"".equals(newValue)) {
317       repository = newValue;
318     }
319     cvs.setRepository(repository);
320 
321     // manifest-store.module
322     //
323     String moduleName = store.getModuleName();
324 
325     if (store instanceof ManifestStore) {
326       moduleName = (moduleName == null ? "manifests" : moduleName);
327       write("[ configurator ] What is the cvs module for the manifest store ? (" + moduleName + ") ");
328     } else {
329       moduleName = (moduleName == null ? "locations" : moduleName);
330       write("[ configurator ] What is the cvs module for the location store ? (" + moduleName + ") ");
331     }
332 
333     newValue = reader.readLine().trim();
334     if (!"".equals(newValue)) {
335       moduleName = newValue;
336     }
337 
338     String name = null;
339     while (moduleName.endsWith(File.separator)) {
340       moduleName.substring(0, name.length());
341     }
342     if (moduleName.lastIndexOf(File.separator) > 0) {
343       store.setModuleName(moduleName.substring(moduleName.lastIndexOf(File.separator) + 1));
344       cvs.setOffset(moduleName.substring(0, moduleName.lastIndexOf(File.separator)));
345     } else {
346       store.setModuleName(moduleName);
347       cvs.setOffset("");
348     }
349 
350     try {
351       checkAuthentication(cvs);
352     } catch (ConfigurationException e) {
353       write("[ configurator ] Error : " + e.getMessage());
354     }
355 
356     // Assign the properties that were asked to the user to the ManifestStore instance.
357     //
358     store.setLocation(cvs);
359 
360     return store;
361   }
362 
363 
364   private void checkAuthentication(VersionControlSystem cvs) throws IOException, ConfigurationException {
365 
366     Authenticator authenticator = null;
367     try {
368       authenticator = Authenticators.getAuthenticator(new AuthenticatorKey(context.getName(), cvs.getId()));
369     } catch (IllegalArgumentException e) {
370       throw new ConfigurationException("The file $HOME/.karma/authenticators.xml seems to be corrupt. Please remove it and try again, karma will generate it for you.", e);
371     } catch (AuthenticationException e) {
372       authenticator = new Authenticator();
373     }
374 
375     authenticator.setWorkingContext(context.getName());
376     authenticator.setId(cvs.getId());
377 
378     String userNameString = (authenticator.getUsername() == null ? "" : "(" + authenticator.getUsername() + ")");
379     String password = "";
380 
381     String newValue = "";
382 
383     while ("".equals(newValue)) {
384       write("[ configurator ] What is your username ? " + userNameString + " : ");
385       newValue = reader.readLine().trim();
386       newValue = ("".equals(newValue) ? authenticator.getUsername() : newValue);
387       authenticator.setUsername(newValue);
388     }
389 
390     if (cvs.getProtocol().equals(CVSRepository.PSERVER)) {
391       writeln("[ configurator ] Password is required, but input is in text-mode. Be warned !");
392       write("[ configurator ] What is your password ? : ");
393       password = reader.readLine().trim();
394       password = ("".equals(password) ? "" : PasswordScrambler.scramble(password));
395     }
396 
397     authenticator.setPassword(password);
398 
399     try {
400       Authenticators.addAuthenticator(authenticator);
401     } catch (AuthenticationException e) {
402       throw new ConfigurationException("The file $HOME/.karma/authenticators.xml seems to be corrupt. Please remove it and try again, karma will generate it for you.", e);
403     }
404   }
405 
406 
407   private void writeln(String text) {
408     System.out.println(text);
409   }
410 
411   private void write(String text) {
412     System.out.print(text);
413   }
414 
415 }